<?php

if (!class_exists('K12Serv_API_Client', false)) {
    if (file_exists(dirname(__FILE__).'/K12Serv_API_Client.class.php')) require_once dirname(__FILE__).'/K12Serv_API_Client.class.php';
    elseif (class_exists('K12Serv_Loader', false)) K12Serv_Loader::loadClass('K12Serv_API_Client');
    else throw new Exception('请先加载类 K12Serv_API_Client。');
}

/**
 * 转换器 API 客户端类。
 *
 * @author Nio Xiao
 * @package K12Conv
 */
class K12Conv_API_Client extends K12Serv_API_Client
{    
    
    /* 转换器类型常量定义 */
    const TYPE_DOC = 'doc';
    const TYPE_PPT = 'ppt';
    const TYPE_PDF = 'pdf';
    const TYPE_IMG = 'img';
    const TYPE_TXT = 'txt';
    const TYPE_VID = 'video';
    const TYPE_FLV = 'flv';
    const TYPE_MP4 = 'mp4';
    
    /**
     * 扩展码与转换器类型对应关系数组。
     * @var array
     */
    private static $ext2types = array(
        'doc'  => self::TYPE_DOC,
        'docx' => self::TYPE_DOC,
        'dot'  => self::TYPE_DOC,
        //'wps'  => self::TYPE_DOC,
        'rtf'  => self::TYPE_DOC,
        'pps'  => self::TYPE_PPT,
        'ppt'  => self::TYPE_PPT,
        'pptx' => self::TYPE_PPT,
        //'wpp'  => self::TYPE_PPT,
        'pdf'  => self::TYPE_PDF,
        'avi'  => self::TYPE_VID,
        'asf'  => self::TYPE_VID,
        'asx'  => self::TYPE_VID,   
        'dat'  => self::TYPE_VID,
        'f4v'  => self::TYPE_VID,
        'hlv'  => self::TYPE_VID,
        'm2t'  => self::TYPE_VID,
        'm2ts' => self::TYPE_VID,
        'm2p'  => self::TYPE_VID,
        'mp4'  => self::TYPE_VID,
        'mpg'  => self::TYPE_VID,
        'mpeg' => self::TYPE_VID,
        'mod'  => self::TYPE_VID,
        'mov'  => self::TYPE_VID,
        'mts'  => self::TYPE_VID,
        'wmv'  => self::TYPE_VID,
        'rm'   => self::TYPE_VID,
        'rmvb' => self::TYPE_VID,
        'dv'   => self::TYPE_VID,
        'mkv'  => self::TYPE_VID,
        '3gp'  => self::TYPE_VID,
        'vob'  => self::TYPE_VID,
        'flv'  => self::TYPE_VID,
        'jpg'  => self::TYPE_IMG,
        'jpeg' => self::TYPE_IMG,
        'gif'  => self::TYPE_IMG,
        'png'  => self::TYPE_IMG,
        'bmp'  => self::TYPE_IMG,
    );
    
    /**
     * 通过调用 API 接口，转换文档，将文档转换成图片及缩略图，也可附加提取文档中的文本信息。
     *
     * @param string $source 原始文档文件所在位置，支持 HTTP 与本地文件，本地文件使用 file://c:/.... 格式。
     * @param string $dest 转换之后的文档存储位置，支持 K12 存储服务与本地文件，K12 存储服务使用 http://ip/service/api/，而本地使用 file://c:/.... 格式。
     * @param boolean $pick_text 是否提取文档中的文本信息，可用于全文检索。
     * @param string $notify_url 转换结果通知地址。
     * @param integer $max_pages 最多转换多少页，0 则表示转换所有页。
     * @param array $cover_options 封面缩略图选项设置，支持的 key 为：
     *                  array(
     *                      'width'   => integer - 缩略图宽度,
     *                      'height'  => integer - 缩略图宽度,
     *                      'crop'    => boolean - 是否按目标尺寸切割图片，若不切割则按比例缩放,
     *                      'quality' => integer - 1~100 的整数，缩略图的质量，100 为最好
     *                  )
     * @return integer|boolean 返回此次调用的请求ID，返回 false 则表示有错误，可通过 getErrorCode() 和 getErrorMessge() 获取错误信息。
     */
    public function convertDocument2Images($source, $dest, $pick_text, $notify_url, $max_pages = 30, $cover_options = array())
    {
        $data = array(
            'action'     => 'converter.doc2imgs',
            'source'     => $source,
            'dest'       => $dest,
            'pick_text'  => $pick_text,
            'notify_url' => $notify_url,
            'max_pages'  => $max_pages,
        );
        $data = $this->addCoverOptions($data, $cover_options);
        $result = $this->callAPI($data);
        return ($result === false) ? false : intval($result['queue_id']);
    }

    /**
     * 通过调用 API 接口，将视频转换成 FLV 格式。
     *
     * @param string $source 原始文档文件所在位置，支持 HTTP 与本地文件，本地文件使用 file://c:/.... 格式。
     * @param string $dest 转换之后的文档存储位置，支持 K12 存储服务与本地文件，K12 存储服务使用 http://ip/service/api/，而本地使用 file://c:/.... 格式。
     * @param string $notify_url 转换结果通知地址。
     * @param integer $endpos 转换时只转前多少秒的视频，0 则转换整个视频。
     * @param array $cover_options 封面缩略图选项设置，支持的 key 为：
     *                  array(
     *                      'width'   => integer - 缩略图宽度,
     *                      'height'  => integer - 缩略图宽度,
     *                      'crop'    => boolean - 是否按目标尺寸切割图片，若不切割则按比例缩放,
     *                      'quality' => integer - 1~100 的整数，缩略图的质量，100 为最好
     *                  )
     * @return integer|boolean 返回此次调用的请求ID，返回 false 则表示有错误，可通过 getErrorCode() 和 getErrorMessge() 获取错误信息。
     */
    public function convertVideo2Flv($source, $dest, $notify_url, $endpos = 300, $cover_options = array())
    {
        $data = array(
            'action'     => 'converter.video2flv',
            'source'     => $source,
            'dest'       => $dest,
            'notify_url' => $notify_url,
            'endpos'     => $endpos,
        );
        $data = $this->addCoverOptions($data, $cover_options);
        $result = $this->callAPI($data);
        return ($result === false) ? false : intval($result['queue_id']);
    }

    /**
     * 通过调用 API 接口，将视频转换成 MP4 格式。
     *
     * @param string $source 原始文档文件所在位置，支持 HTTP 与本地文件，本地文件使用 file://c:/.... 格式。
     * @param string $dest 转换之后的文档存储位置，支持 K12 存储服务与本地文件，K12 存储服务使用 http://ip/service/api/，而本地使用 file://c:/.... 格式。
     * @param string $notify_url 转换结果通知地址。
     * @param integer $endpos 转换时只转前多少秒的视频，0 则转换整个视频。
     * @param array $cover_options 封面缩略图选项设置，支持的 key 为：
     *                  array(
     *                      'width'   => integer - 缩略图宽度,
     *                      'height'  => integer - 缩略图宽度,
     *                      'crop'    => boolean - 是否按目标尺寸切割图片，若不切割则按比例缩放,
     *                      'quality' => integer - 1~100 的整数，缩略图的质量，100 为最好
     *                  )
     * @return integer|boolean 返回此次调用的请求ID，返回 false 则表示有错误，可通过 getErrorCode() 和 getErrorMessge() 获取错误信息。
     */
    public function convertVideo2Mp4($source, $dest, $notify_url, $endpos = 300, $cover_options = array())
    {
        $data = array(
            'action'     => 'converter.video2mp4',
            'source'     => $source,
            'dest'       => $dest,
            'notify_url' => $notify_url,
            'endpos'     => $endpos,
        );
        $data = $this->addCoverOptions($data, $cover_options);
        $result = $this->callAPI($data);
        return ($result === false) ? false : intval($result['queue_id']);
    }

    /**
     * 通过调用 API 接口，缩放图片。
     *
     * @param string $source 原始文档文件所在位置，支持 HTTP 与本地文件，本地文件使用 file://c:/.... 格式。
     * @param string $dest 转换之后的文档存储位置，支持 K12 存储服务与本地文件，K12 存储服务使用 http://ip/service/api/，而本地使用 file://c:/.... 格式。
     * @param string $notify_url 转换结果通知地址。
     * @param integer $width 目标图片宽度。
     * @param integer $height 目标图片高度。
     * @param boolean $crop 是否按目标尺寸切割图片，若不切割则按比例缩放。
     * @param array $cover_options 封面缩略图选项设置，支持的 key 为：
     *                  array(
     *                      'width'   => integer - 缩略图宽度,
     *                      'height'  => integer - 缩略图宽度,
     *                      'crop'    => boolean - 是否按目标尺寸切割图片，若不切割则按比例缩放,
     *                      'quality' => integer - 1~100 的整数，缩略图的质量，100 为最好
     *                  )
     * @return integer|boolean 返回此次调用的请求ID，返回 false 则表示有错误，可通过 getErrorCode() 和 getErrorMessge() 获取错误信息。
     */
    public function resizeImage($source, $dest, $notify_url, $width = 600, $height = 400, $crop = false, $cover_options = array())
    {
        $data = array(
            'action'     => 'converter.resize',
            'source'     => $source,
            'dest'       => $dest,
            'notify_url' => $notify_url,
            'width'      => $width,
            'height'     => $height,
            'crop'       => $crop
        );
        $data = $this->addCoverOptions($data, $cover_options);
        $result = $this->callAPI($data);
        return ($result === false) ? false : intval($result['queue_id']);
    }
    
    /**
     * 通过调用 API 接口，对视频的时间点序列进行抓取图片。
     *
     * @param string $source 原始文档文件所在位置，支持 HTTP 与本地文件，本地文件使用 file://c:/.... 格式。
     * @param string $dest 转换之后的文档存储位置，支持 K12 存储服务与本地文件，K12 存储服务使用 http://ip/service/api/，而本地使用 file://c:/.... 格式。
     * @param string $notify_url 转换结果通知地址。
     * @param string $video_pos 需要抓取的时间点序列，时间点单位为秒，多个时间点使用英文逗号分割，如：10,20,25。
     * @param integer $width 目标图片宽度。
     * @param integer $height 目标图片高度。
     * @return integer|boolean 返回此次调用的请求ID，返回 false 则表示有错误，可通过 getErrorCode() 和 getErrorMessge() 获取错误信息。
     */
    public function convertVideo2Images($source, $dest, $notify_url, $video_pos, $width = 600, $height = 400)
    {
        $data = array(
            'action'     => 'converter.video2imgs',
            'source'     => $source,
            'dest'       => $dest,
            'notify_url' => $notify_url,
            'video_pos'  => $video_pos,
            'width'      => $width,
            'height'     => $height,
        );
        $result = $this->callAPI($data);
        return ($result === false) ? false : intval($result['queue_id']);
    }    
    
    /**
     * 原始文件是否为文档类型。
     *
     * @param string $source 需要转换的文件名，包括完全物理路径。
     * @return boolean
     */
    public static function isDocument($source)
    {
        $source_type = self::getSourceType($source);
        return in_array($source_type, array(
            self::TYPE_DOC, self::TYPE_PPT, self::TYPE_PDF
        ));
    }
    
    /**
     * 原始文件是否为视频类型。
     *
     * @param string $source 需要转换的文件名，包括完全物理路径。
     * @return boolean
     */
    public static function isVideo($source)
    {
        $source_type = self::getSourceType($source);
        return $source_type == self::TYPE_VID;
    }
    
    /**
     * 原始文件是否为图片类型。
     *
     * @param string $source 需要转换的文件名，包括完全物理路径。
     * @return boolean
     */
    public static function isImage($source)
    {
        $source_type = self::getSourceType($source);
        return $source_type == self::TYPE_IMG;
    }    
    
    /**
     * 获取原始文件类型。
     *
     * @param string $source 需要转换的文件名，包括完全物理路径。
     * @return string 返回对应的类型字符串，未找到类型则返回空字符串。
     */
    public static function getSourceType($source)
    {
        $ext = parent::getExt($source);
        if (!isset(self::$ext2types[$ext])) return '';
        else return self::$ext2types[$ext];    
    }    
    
    /**
     * 将时间字符串转换成秒数。
     *
     * @param string $str 时间字符串，格式为“HH:MM:SS”，如1小时25秒为 01:00:25 或 1:00:25，2分钟30秒为 00:02:30 或 02:30。
     * @return integer 返回转换之后对应的秒数。
     */
    public static function str2Seconds($str)
    {
        $arr = explode(':', $str);
        $arr = array_reverse($arr);
        $seconds = 0;
        if (count($arr) == 3) $seconds += intval($arr[2]) * 3600;
        if (count($arr) >= 2) $seconds += intval($arr[1]) * 60;
        $seconds += intval($arr[0]);
        return $seconds;
    }
    
    /**
     * 将秒数转换成时间字符串。
     *
     * @param integer $seconds 秒数。
     * @return string 返回时间字符串，格式为“HH:MM:SS”，如1小时25秒为 01:00:25，2分钟30秒为 02:30，25秒为 00:25。
     */
    public static function second2Str($seconds)
    {
        $arr = array();
        if ($seconds >= 3600) { //小时
            $h = intval($seconds / 3600); 
            $seconds -= $h * 3600; 
            $arr[] = sprintf('%02d', $h);
        }
        if ($seconds >= 60) { //分钟
            $m = intval($seconds / 60); 
            $seconds -= $m * 60;
            $arr[] = sprintf('%02d', $m);
        } else {
            $arr[] = '00';
        }
        $arr[] = sprintf('%02d', $seconds); //秒
        return implode(':', $arr);
    }
    
    /**
     * 添加封面缩略图参数设置。
     *
     * @param array $data 原有需要传递的参数数据数组。
     * @param array $cover_options 封面参数设置数组。
     * @return array
     */
    private function addCoverOptions($data, $cover_options)
    {
        foreach (array('width', 'height', 'crop', 'quality') as $k) {
            if (isset($cover_options[$k])) $data['cover_'.$k] = $cover_options[$k];
        }    
        return $data;
    }
}
